namespace Legend.Web.QueryString
{
    using System;
    using System.ComponentModel;
    using Legend.Reflection;

    /// <summary>
    /// Provides information for a member that can
    /// be serialized.
    /// </summary>
    public class SerializableMemberInfo
        : IComparable<SerializableMemberInfo>
    {
        private ValueMemberInfo memberInfo;

        /// <summary>
        /// Creates a new instance.
        /// </summary>
        /// <param name="name">The name of the serializable member.</param>
        /// <param name="converter">The converter to use to convert the values of the member.</param>
        /// <param name="memberInfo">The member info to use to access the values of the member.</param>
        /// <param name="order">The order of serialization for the member.</param>
        public SerializableMemberInfo(string name, TypeConverter converter, ValueMemberInfo memberInfo, int order)
        {
            this.Name = name;
            this.Converter = converter;
            this.memberInfo = memberInfo;

            if (order > -1)
            {
                this.Order = order;
            }
        }

        /// <summary>
        /// The name of the member in the contract.
        /// </summary>
        public readonly string Name;

        /// <summary>
        /// The type converter to use when converting the
        /// value of the member to and from a string.
        /// </summary>
        public readonly TypeConverter Converter;

        /// <summary>
        /// The specified order of the member, null
        /// if the order is not specified.
        /// </summary>
        public readonly int? Order;

        /// <summary>
        /// The <see cref="Type" /> of the member.
        /// </summary>
        public Type ContractMemberType
        {
            get
            {
                return this.memberInfo.ValueType;
            }
        }

        /// <summary>
        /// Sets the value of the member on the object
        /// specified in the item parameter.
        /// </summary>
        /// <param name="item">The item to set the member on.</param>
        /// <param name="value">The value to set to the member.</param>
        public void SetValue(object item, object value)
        {
            this.memberInfo.SetValue(item, value);
        }

        /// <summary>
        /// Gets the value of the member from the object
        /// specified in the item parameter.
        /// </summary>
        /// <param name="item">The item to get the value from.</param>
        /// <returns>The value of the member.</returns>
        public object GetValue(object item)
        {
            return this.memberInfo.GetValue(item);
        }

        /// <summary>
        /// Compares the current object with another object of the same type.
        /// </summary>
        /// <returns>
        /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other" /> parameter.Zero This object is equal to <paramref name="other" />. Greater than zero This object is greater than <paramref name="other" />. 
        /// </returns>
        /// <param name="other">An object to compare with this object.</param>
        public int CompareTo(SerializableMemberInfo other)
        {
            if (this.Order != null && other.Order != null)
            {
                return this.Order.Value - other.Order.Value;
            }

            if (this.Order != null && other.Order == null)
            {
                return 1;
            }

            if (this.Order == null && other.Order != null)
            {
                return -1;
            }

            return string.CompareOrdinal(this.Name, other.Name);
        }
    }
}